﻿using Microsoft.AspNetCore.SignalR;

using PLCS.Application.EquipmentApp.Hubs;
using PLCS.Domain.Equipments;
using PLCS.Domain.Logs;
using PLCS.Domain.Shared.Enums;
using PLCS.Domain.Shared.PLCConfigs;
using PLCS.Domain.Shared.Tasks;
using PLCS.Domain.Stations;
using PLCS.Domain.Tasks;
using PLCS.Domain.Trays;
using PLCS.EntityFrameworkCore.EntityFrameworkCore;
using PLCS.PlcInteraction;
using PLCS.Shared.Common.Constant;
using PLCS.SocialHttpClient.WMS;

using Volo.Abp.Domain.Entities;
using Volo.Abp.EntityFrameworkCore;

namespace PLCS.Web.EventHandlers;

public class PLCReadDataValueChangeHandler : ILocalEventHandler<PLCReadDataValueChangeEvent>, ITransientDependency
{
    private readonly IEquipmentRepository _equipmentRepository;
    private readonly IStationRepository _stationRepository;
    private readonly ILogger<PLCReadDataValueChangeHandler> _logger;
    private readonly IInstructionRepository _instructionRepository;
    private readonly TaskManager _taskManager;
    private readonly ITaskRepository _taskRepository;
    private readonly ITrayRepository _trayRepository;
    private readonly IDbContextProvider<PLCSDbContext> _dbContextProvider;
    private readonly IHubContext<FrameHub> _hubcontext;
    private readonly WMSSocialService _wMSSocialService;
    private readonly ErrorLogManager _errorLogManager;
    private readonly PLCWriter _plcWriter;

    public PLCReadDataValueChangeHandler(IEquipmentRepository equipmentRepository,
        IStationRepository stationRepository,
        ILogger<PLCReadDataValueChangeHandler> logger,
        IInstructionRepository instructionRepository,
        TaskManager taskManager,
        ITaskRepository taskRepository,
        IDbContextProvider<PLCSDbContext> dbContextProvider,
        IHubContext<FrameHub> hubcontext,
        ITrayRepository trayRepository,
        WMSSocialService wMSSocialService,
        ErrorLogManager errorLogManager,
        PLCWriter plcWriter)
    {
        _equipmentRepository = equipmentRepository;
        _stationRepository = stationRepository;
        _logger = logger;
        _instructionRepository = instructionRepository;
        _taskManager = taskManager;
        _taskRepository = taskRepository;
        _dbContextProvider = dbContextProvider;
        _hubcontext = hubcontext;
        _trayRepository = trayRepository;
        _wMSSocialService = wMSSocialService;
        _errorLogManager = errorLogManager;
        _plcWriter = plcWriter;
    }

    public async Task HandleEventAsync(PLCReadDataValueChangeEvent eventData)
    {
        switch (eventData.CorrespondingType)
        {
            case "CompletionSignal":
               // await HandleCompletionSignal(eventData);
                break;

            case "UpdateCanOutAndInStatus":
                await UpdateCanOutAndInStatus(eventData);
                break;

            case "ButtonConveyEvent":
                await HandleButtonConveyEvent(eventData);
                break;

            case "StationHaveStatus":
                await HandleStationHaveStatus(eventData);
                break;

            case "EuipmentStatus":
                await HandleEquipmentStatus(eventData);
                break;

            case "CurrentStation":
                await HandleCurrentStation(eventData);
                break;

            case "ScanAndStore":
                await HandScanAndStore(eventData);
                break;

            case "OnCranePositionChanged":
                await HandOnCranePositionChanged(eventData);
                break;
        }
    }

    private async Task UpdateCanOutAndInStatus(PLCReadDataValueChangeEvent eventData)
    {
        if (string.IsNullOrWhiteSpace(eventData.WhereValue) || string.IsNullOrWhiteSpace(eventData.WhereField) || string.IsNullOrWhiteSpace(eventData.CorrespondingField))
            return;
        try
        {
            var station = await _stationRepository.GetStationByNumAsync(eventData.WhereValue);
            if (station == null)
            {
                _logger.LogError($"{eventData.WhereValue}工位不存在");
                return;
            }
            if (eventData.WhereField == "CanOut")
                station.UpdateCanOutStatus(eventData.CorrespondingField, (YesNo)int.Parse(eventData.CurrentValue));
            else if (eventData.WhereField == "CanInSide")
                station.UpdateCanInStatus(eventData.CorrespondingField, (YesNo)int.Parse(eventData.CurrentValue));
            else
            {
                _logger.LogError($"修改状态类型异常");
                return;
            }
            await _stationRepository.UpdateAsync(station);
        }
        catch (Exception ex)
        {
            _logger.LogError($"UpdateCanOutAndInStatus事件处理异常，异常信息：{ex.Message}");
        }
    }

    /// <summary>
    /// 堆垛机位置改变事件（根据列）
    /// </summary>
    /// <param name="eventData"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    private async Task HandOnCranePositionChanged(PLCReadDataValueChangeEvent eventData)
    {
        if (string.IsNullOrWhiteSpace(eventData.WhereValue) || string.IsNullOrWhiteSpace(eventData.WhereField) || string.IsNullOrWhiteSpace(eventData.CurrentValue) || eventData.CurrentValue == "0")
            return;
        try
        {
            await _hubcontext.Clients.All.SendAsync("ChangeCranePosition", eventData.WhereField, eventData.WhereValue, eventData.CurrentValue);
        }
        catch (Exception ex)
        {
            _logger.LogError($"HandOnCranePositionChanged，异常信息：{ex.Message}");
        }
    }

    /// <summary>
    /// 扫码入库事件
    /// </summary>
    /// <param name="eventData"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    private async Task HandScanAndStore(PLCReadDataValueChangeEvent eventData)
    {
        var stationNum = eventData.WhereValue;
        var trayNo = eventData.CurrentValue;
        if (trayNo == "0" || string.IsNullOrEmpty(stationNum))
            return;

        // 1.判断数据库中有没有这个托盘，没有则添加
        // 2.判断货物类型
        // 3.创建任务

        try
        {
            var task = await _taskRepository.FindAsync(x => x.StartPos == stationNum && x.TrayNo == trayNo);
            if (task != null)
                return;

            var station = await _stationRepository.GetStationByNumAsync(stationNum);
            if (station == null)
                return;
            var currentMaterialSize = station.CurrentMaterialSize == 0 ? 5 : station.CurrentMaterialSize;
            var tray = await _trayRepository.GetTrayByNoAsync(trayNo);
            if (tray != null)
            {
                tray.MaterialSize = currentMaterialSize;
                if (tray.Station != null)
                {
                    await _errorLogManager.AddErrorLogAsync(new ErrorLog("E", $"托盘号‘{trayNo}’在库中有一条记录，在'{tray.Station.StaNum}'，现已修改，请注意维护", "PLCS", "业务"));
                    tray.StationId = null;
                }
                await _trayRepository.UpdateAsync(tray);
            }
            else
            {
                tray = await _trayRepository.InsertAsync(new Tray(trayNo, TrayType.未知));
            }

            // 如果原先有记录到此工位的托盘号，那就移除掉，因为肯定以扫码的为准
            if (station.Trays != null && station.Trays.Any())
                station.RemoveTray();

            // 将托盘放入起始工位，并将起始工位更新到数据库
            station.AddTray(tray);
            await _stationRepository.UpdateAsync(station);

            if (LocalConfigManager.IsWMS)
            {
                var result = await _wMSSocialService.RequestWarehousingAsync(stationNum, trayNo);
                if (result.Header.Code == "E")
                    await _errorLogManager.AddErrorLogAsync(new ErrorLog("WMS", $"请求入库接口调用异常，异常信息：{result.Header.Message}", "WMS接口调用", "通讯"));
            }
            else
                await _taskManager.InsertAsync(new TaskModel(0, 0, stationNum, "", null, TaskType.入库, "扫码入库", trayNo));
        }
        catch (Exception ex)
        {
            _logger.LogError($"HandScanAndStore事件处理异常，异常信息：{ex.Message}");
        }
    }

    /// <summary>
    /// 按钮触发输送任务事件
    /// </summary>
    /// <param name="eventData"></param>
    /// <returns></returns>
    private async Task HandleButtonConveyEvent(PLCReadDataValueChangeEvent eventData)
    {
        var startPos = eventData.WhereField;
        var endPos = eventData.WhereValue;
        var currentValue = eventData.CurrentValue;
        if (currentValue != "1" || string.IsNullOrEmpty(startPos) || string.IsNullOrEmpty(endPos))
            return;
        try
        {
            var starts = startPos.Split('，');
            foreach (var item in starts)
            {
                // 1.获取起始位和目标位置，判断是否存在
                var start = await _stationRepository.GetStationByNumAsync(item);
                if (start == null || start.HaveStatus == YesNo.否)
                {
                    _logger.LogWarning($"起始位{item}不存在或空位");
                    continue;
                }
                var end = await _stationRepository.GetStationByNumAsync(endPos);
                if (end == null)
                {
                    _logger.LogWarning($"目标位{endPos}不存在");
                    continue;
                }
                // 2.获取起始位上的托盘
                var trayNo = start.GetTray()?.TrayNo;
                if (string.IsNullOrEmpty(trayNo))
                    _logger.LogWarning($"起始位{startPos}上的托盘号为空");
                // 3.插入一条任务
                var task = new TaskModel(0, 0, item, endPos, null, TaskType.普通流转, "按钮触发", trayNo);
                await _taskManager.InsertAsync(task);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError($"HandleButtonConveyEvent事件处理异常，异常信息：{ex.Message}");
        }
    }

    /// <summary>
    /// 处理完成信号
    /// </summary>
    /// <param name="eventData"></param>
    /// <returns></returns>
    private async Task HandleCompletionSignal(PLCReadDataValueChangeEvent eventData)
    {
        if (eventData.CurrentValue != "1")
            return;

        try
        {
            // 1.获取设备
            var equipment = await _equipmentRepository.GetAsync(x => x.EquNum == eventData.WhereValue);
            // 2.写plc确认收到信号
            _plcWriter.ConfirmComplete(equipment.Plc_Index, equipment.PLCAddress, equipment.Rack, equipment.Slot, equipment.DbNumber);

            // 3.获取设备的当前指令号
            var instructionNo = equipment.CurrentTaskId;
            // 4.通过指令号获取指令实体
            var instruction = await _instructionRepository.FindAsync(x => x.InstructionNo == instructionNo);
            if (instruction == null)
            {
                _logger.LogError($"HandleCompletionSignal事件处理异常，异常信息：未找到指令Id'{instructionNo}'");
                return;
            };
            // 5.将指令修改为已完成
            instruction.ChangeStatus(Domain.Shared.Tasks.InstructionStatus.已完成);
            await _instructionRepository.UpdateAsync(instruction);
            _logger.LogInformation($"通过读取{equipment.EquNum}设备号的完成信号，已将设备的当前指令'{instruction.InstructionNo}'置为已完成");
        }
        catch (Exception ex)
        {
            _logger.LogError($"HandleCompletionSignal事件处理异常，异常信息：{ex.Message}");
        }
    }

    /// <summary>
    /// 处理工位有料状态（通知前端界面）
    /// </summary>
    /// <param name="eventData"></param>
    /// <returns></returns>
    private async Task HandleStationHaveStatus(PLCReadDataValueChangeEvent eventData)
    {
        if (string.IsNullOrWhiteSpace(eventData.WhereValue) || string.IsNullOrWhiteSpace(eventData.CurrentValue))
            return;

        try
        {
            await _hubcontext.Clients.All.SendAsync("ChangeStationStatus", eventData.WhereValue, (YesNo)int.Parse(eventData.CurrentValue));
        }
        catch (Exception ex)
        {
            _logger.LogError($"HandleStationHaveStatus事件处理异常，异常信息：{ex.Message}");
        }
    }

    /// <summary>
    /// 处理设备状态（通知前端界面）
    /// </summary>
    /// <param name="eventData"></param>
    /// <returns></returns>
    private async Task HandleEquipmentStatus(PLCReadDataValueChangeEvent eventData)
    {
        if (string.IsNullOrWhiteSpace(eventData.WhereValue) || string.IsNullOrWhiteSpace(eventData.CurrentValue))
            return;

        try
        {
            await _hubcontext.Clients.All.SendAsync("ChangeEquipmentStatus", eventData.WhereValue, (YesNo)int.Parse(eventData.CurrentValue));
        }
        catch (Exception ex)
        {
            _logger.LogError($"HandleEquipmentStatus事件处理异常，异常信息：{ex.Message}");
        }
    }

    /// <summary>
    /// 处理设备当前工位（通知前端界面）
    /// </summary>
    /// <param name="eventData"></param>
    /// <returns></returns>
    private async Task HandleCurrentStation(PLCReadDataValueChangeEvent eventData)
    {
        if (string.IsNullOrWhiteSpace(eventData.WhereValue) || string.IsNullOrWhiteSpace(eventData.CurrentValue) || eventData.CurrentValue == "0")
            return;
        try
        {
            var currentStation = await _stationRepository.GetStationByNumAsync(eventData.CurrentValue, 0);
            if (currentStation == null)
            {
                _logger.LogWarning($"HandleCurrentStation事件处理异常，未查询到工位{eventData.CurrentValue}");
                return;
            }

            await _hubcontext.Clients.All.SendAsync("ChangeEquipmentLocation", eventData.WhereValue, currentStation.StaNum);
        }
        catch (Exception ex)
        {
            _logger.LogError($"HandleCurrentStation事件处理异常，异常信息：{ex.Message}");
        }
    }
}